﻿package hanoi {
	/**
	 * Una torre del juego de las torres de Hanoi.
	 */
	public final class Tower {
		/**
		 * Mensaje de error para movidas que usan como destino una torre de otro juego.
		 */
		private static const DIFFERENT_OWNER:String = "La torre destino pertenece a otro juego";
		/**
		 * Mensaje de error para movidas desde torres que no le quedan discos.
		 */
		private static const NO_DISC:String = "La torre no tiene discos";
		/**
		 * Mensaje de error para movidas de un disco sobre otro más chico.
		 */
		private static const DISC_TOO_BIG:String = "El disco es más grande que el disco en la otra torre";
		
		/**
		 * El juego al que pertenece esta torre.
		 */
		private var _owner:Hanoi;
		/**
		 * Los discos en esta torre.
		 */
		private var discs:Array;
		
		/**
		 * Constructor.
		 * @param owner El juego al que pertenece esta torre.
		 * @param discsQuantity Cantidad de discos con los que empieza la torre.
		 */
		public function Tower(owner:Hanoi, discsQuantity:uint = 0):void {
			_owner = owner;
			discs = new Array();
			for (var i:uint = discsQuantity; i > 0; i--) {
				discs.push(new Disc(i));
			}
		}
		
		/**
		 * El juego al que pertenece esta torre.
		 */
		public function get owner():Hanoi {
			return _owner;
		}
		
		/**
		 * Verdadero si la torre no tiene discos.
		 */
		public function get empty():Boolean {
			return discs.length == 0;
		}
		
		/**
		 * El disco en la cima de la torre.
		 */
		public function get top():Disc {
			return discs[discs.length - 1];
		}
		
		/**
		 * Mueve el primer disco a otra torre.
		 * @param target La otra torre.
		 * @throws hanoi.BadMove
		 */
		public function moveDiscTo(target:Tower):void {
			if (this == target) return;
			if (target.owner != this.owner) throw new BadMove(DIFFERENT_OWNER);
			if (this.empty) throw new BadMove(NO_DISC);
			if (!target.empty && target.top.size < this.top.size) throw new BadMove(DISC_TOO_BIG);
			owner.dispatchEvent(new HanoiEvent(HanoiEvent.DISC_MOVED, owner, this.top, this, target));
			target.discs.push(this.discs.pop());
		}
		
		/**
		 * Representación textual del objeto.
		 */
		public function toString():String {
			var str:String = "[Tower";
			for (var i:int = 0; i < discs.length; i++) {
				str += " " + discs[i];
			}
			str += "]";
			return str;
		}
	}
}
